//
// Created by kylin on 23-4-2.
//

#ifndef FCITX_SERVER_H
#define FCITX_SERVER_H
#include "eim.h"
#include "httplib.h"
#include <sys/wait.h>

void start_process(FcitxEn *en);
void set_server(FcitxEn *en);

void start_process(FcitxEn *en) {
    /* exec command */
    pid_t child_pid;

    child_pid = fork();
    if (child_pid < 0) {
        perror("fork");
    } else if (child_pid == 0) { /* child process  */
        setsid();
        pid_t grandchild_pid;

        grandchild_pid = fork();
        if (grandchild_pid < 0) {
            perror("fork");
            _exit(1);
        } else if (grandchild_pid == 0) { /* grandchild process  */
            set_server(en);
            perror("set_server");
            _exit(1);
        } else {
            _exit(0);
        }
    } else { /* parent process */
        int status;
        waitpid(child_pid, &status, 0);
    }
}

void set_server(FcitxEn *en) {
    en->server->set_default_headers(
        {{"Access-Control-Allow-Origin", "*"},
         {"Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE"},
         {"Access-Control-Max-Age", "3600"},
         {"Access-Control-Allow-Headers", "*"},
         {"Content-Type", "application/json;charset=utf-8"}});

    en->server->Options("/today",
                        [](const httplib::Request &, httplib::Response &resp) {
                            resp.status = 200;
                        });
    en->server->Get("/today", [&en](const httplib::Request &req,
                                    httplib::Response &res) {
        if (req.params.empty()) {
            res.set_content(
                "{\"state\":" +
                    to_string(en->engine->imConfig->get_today_input()) + "}",
                "application/json");
        } else {
            res.set_content("{\"code\":300}", "application/json");
        }
    });

    en->server->Options("/total",
                        [](const httplib::Request &, httplib::Response &resp) {
                            resp.status = 200;
                        });

    en->server->Get("/total", [&en](const httplib::Request &req,
                                    httplib::Response &res) {
        if (req.params.empty()) {
            res.set_content(
                "{\"state\":" +
                    to_string(en->engine->imConfig->get_total_input()) + "}",
                "application/json");
        } else {
            res.set_content("{\"code\":300}", "application/json");
        }
    });

    en->server->Options("/kpm",
                        [](const httplib::Request &, httplib::Response &resp) {
                            resp.status = 200;
                        });

    en->server->Get(
        "/kpm", [&en](const httplib::Request &req, httplib::Response &res) {
            if (req.params.empty()) {
                res.set_content(
                    "{\"state\":" + to_string(en->engine->imConfig->get_kpm()) +
                        "}",
                    "application/json");
            } else {
                res.set_content("{\"code\":300}", "application/json");
            }
        });

    en->server->Options("/rank",
                        [](const httplib::Request &, httplib::Response &resp) {
                            resp.status = 200;
                        });

    en->server->Get(
        "/rank", [&en](const httplib::Request &req, httplib::Response &res) {
            if (req.params.empty()) {
                res.set_content(
                    "{\"state\":" +
                        to_string(int(en->engine->imConfig->get_rank())) + "}",
                    "application/json");
            } else {
                res.set_content("{\"code\":300}", "application/json");
            }
        });

    en->server->Options("/font",
                        [](const httplib::Request &, httplib::Response &resp) {
                            resp.status = 200;
                        });

    en->server->Get("/font", [&en](const httplib::Request &req,
                                   httplib::Response &res) {
        if (req.has_param("value")) {
            auto val = req.get_param_value("value");
            en->engine->imConfig->set_font(stoi(val));
            res.set_content("{\"code\":200}", "application/json");
        } else if (req.params.empty()) {
            res.set_content(
                "{\"state\":" + to_string(en->engine->imConfig->get_font()) +
                    "}",
                "application/json");
        } else {
            res.set_content("{\"code\":300}", "application/json");
        }
    });

    en->server->Options("/code",
                        [](const httplib::Request &, httplib::Response &resp) {
                            resp.status = 200;
                        });

    en->server->Get("/code", [&en](const httplib::Request &req,
                                   httplib::Response &res) {
        if (req.has_param("value")) {
            string val = req.get_param_value("value");
            en->engine->imConfig->set_code_switch(val == "1");
            cout << val << "  code_switch   "
                 << en->engine->imConfig->get_code_switch() << endl;
            res.set_content("{\"code\":200}", "application/json");
        } else if (req.params.empty()) {
            string tmp = en->engine->imConfig->get_code_switch() ? "1" : "2";
            res.set_content("{\"state\":" + tmp + "}", "application/json");
        } else {
            res.set_content("{\"code\":300}", "application/json");
        }
    });

    en->server->Options("/key",
                        [](const httplib::Request &, httplib::Response &resp) {
                            resp.status = 200;
                        });

    en->server->Get("/key", [&en](const httplib::Request &req,
                                  httplib::Response &res) {
        if (req.has_param("value")) {
            auto val = req.get_param_value("value");
            en->engine->imConfig->set_key_switch(val == "1");
            cout << "key   " << en->engine->imConfig->get_key_switch() << endl;
            res.set_content("{\"code\":200}", "application/json");
        } else if (req.params.empty()) {
            string tmp = en->engine->imConfig->get_key_switch() ? "1" : "2";
            res.set_content("{\"state\":" + tmp + "}", "application/json");
        } else {
            res.set_content("{\"code\":300}", "application/json");
        }
    });

    en->server->Options("/mohu",
                        [](const httplib::Request &, httplib::Response &resp) {
                            resp.status = 200;
                        });

    en->server->Get("/mohu", [&en](const httplib::Request &req,
                                   httplib::Response &res) {
        if (!req.params.empty()) {
            if (req.has_param("mohu_1")) {
                auto val = req.get_param_value("mohu_1");
                en->engine->imConfig->set_search_switch_vq(val == "1");
            }
            if (req.has_param("mohu_2")) {
                auto val = req.get_param_value("mohu_2");
                en->engine->imConfig->set_search_switch_ou(val == "1");
            }
            if (req.has_param("mohu_3")) {
                auto val = req.get_param_value("mohu_3");
                en->engine->imConfig->set_search_switch_td(val == "1");
            }
            if (req.has_param("mohu_4")) {
                auto val = req.get_param_value("mohu_4");
                en->engine->imConfig->set_search_switch_hg(val == "1");
            }
            if (req.has_param("mohu_5")) {
                auto val = req.get_param_value("mohu_5");
                en->engine->imConfig->set_search_switch_eE(val == "1");
            }
            if (req.has_param("mohu_6")) {
                auto val = req.get_param_value("mohu_6");
                en->engine->imConfig->set_search_switch_wE(val == "1");
            }
            if (req.has_param("mohu_7")) {
                auto val = req.get_param_value("mohu_7");
                en->engine->imConfig->set_search_switch_ngN(val == "1");
            }
            if (req.has_param("mohu_8")) {
                auto val = req.get_param_value("mohu_8");
                en->engine->imConfig->set_search_switch_sixi(val == "1");
            }
            res.set_content("{\"code\":200}", "application/json");
        } else if (req.params.empty()) {
            string tmp = "{";
            tmp += "\"mohu_1\":";
            tmp +=
                en->engine->imConfig->get_search_switch_vq() ? "true" : "false";
            tmp += ",\"mohu_2\":";
            tmp +=
                en->engine->imConfig->get_search_switch_ou() ? "true" : "false";
            tmp += ",\"mohu_3\":";
            tmp +=
                en->engine->imConfig->get_search_switch_td() ? "true" : "false";
            tmp += ",\"mohu_4\":";
            tmp +=
                en->engine->imConfig->get_search_switch_hg() ? "true" : "false";
            tmp += ",\"mohu_5\":";
            tmp +=
                en->engine->imConfig->get_search_switch_eE() ? "true" : "false";
            tmp += ",\"mohu_6\":";
            tmp +=
                en->engine->imConfig->get_search_switch_wE() ? "true" : "false";
            tmp += ",\"mohu_7\":";
            tmp += en->engine->imConfig->get_search_switch_ngN() ? "true"
                                                                 : "false";
            tmp += ",\"mohu_8\":";
            tmp += en->engine->imConfig->get_search_switch_sixi() ? "true"
                                                                  : "false";
            tmp += "}";
            res.set_content(tmp, "application/json");
        } else {
            res.set_content("{\"code\":300}", "application/json");
        }
    });

    en->server->Options("/phrase",
                        [](const httplib::Request &, httplib::Response &resp) {
                            resp.status = 200;
                        });
    en->server->Get(
        "/phrase", [&en](const httplib::Request &req, httplib::Response &res) {
            if (req.has_param("page")) {
                auto val = req.get_param_value("page");
                string result = en->engine->get_quick_phrase_by_page(stoi(val));
                res.set_content(result, "application/json");
            } else if (req.params.empty()) {
                auto val = req.get_param_value("page");
                string result = en->engine->get_quick_phrase_by_page(-1);
                res.set_content(result, "application/json");
            } else {
                res.set_content("{\"code\":300}", "application/json");
            }
        });

    en->server->Options("/new_phrase",
                        [](const httplib::Request &, httplib::Response &resp) {
                            resp.status = 200;
                        });
    en->server->Get("/new_phrase", [&en](const httplib::Request &req,
                                         httplib::Response &res) {
        if (req.params.size() == 3) {
            string abbr = req.get_param_value("abbr");
            string phrase = req.get_param_value("phrase");
            int position = stoi(req.get_param_value("position"));
            if (en->engine->insert_quick_phrase(abbr, phrase, position) &&
                en->engine->insert_quick_phrase_in_file(abbr, phrase, position))
                res.set_content("{\"code\":200}", "application/json");
            else
                res.set_content("{\"code\":201}", "application/json");
        } else {
            res.set_content("{\"code\":300}", "application/json");
        }
    });

    en->server->Options("/delete_phrase",
                        [](const httplib::Request &, httplib::Response &resp) {
                            resp.status = 200;
                        });
    en->server->Get("/delete_phrase", [&en](const httplib::Request &req,
                                            httplib::Response &res) {
        if (req.params.size() == 1) {
            string phrase = req.get_param_value("phrase");
            if (en->engine->remove_quick_phrase(phrase) &&
                en->engine->remove_quick_phrase_in_file(phrase))
                res.set_content("{\"code\":200}", "application/json");
            else
                res.set_content("{\"code\":201}", "application/json");
        } else {
            res.set_content("{\"code\":300}", "application/json");
        }
    });

    en->server->Options("/update_phrase",
                        [](const httplib::Request &, httplib::Response &resp) {
                            resp.status = 200;
                        });
    en->server->Get("/update_phrase", [&en](const httplib::Request &req,
                                            httplib::Response &res) {
        if (req.params.size() == 4) {
            string abbr = req.get_param_value("abbr");
            string old_phrase = req.get_param_value("old_phrase");
            string new_phrase = req.get_param_value("new_phrase");
            int position = stoi(req.get_param_value("position"));
            cout<<abbr<<" "<<old_phrase<<" "<<new_phrase<<" "<<position<<endl;
            if (en->engine->modify_quick_phrase(abbr, old_phrase, new_phrase,
                                                position) &&
                en->engine->modify_quick_phrase_in_file(abbr, old_phrase,
                                                        new_phrase, position))
                res.set_content("{\"code\":200}", "application/json");
            else
                res.set_content("{\"code\":201}", "application/json");
        } else {
            res.set_content("{\"code\":300}", "application/json");
        }
    });
    en->server->Options("/key1",
                        [](const httplib::Request &, httplib::Response &resp) {
                            resp.status = 200;
                        });

    en->server->Get("/key1", [&en](const httplib::Request &req,
                                  httplib::Response &res) {
        if (req.has_param("value")) {
            auto val = req.get_param_value("value");
            en->engine->imConfig->set_key_switch(val == "1");
            cout << "key   " << en->engine->imConfig->get_key_switch() << endl;
            res.set_content("{\"code\":200}", "application/json");
        } else if (req.params.empty()) {
            string tmp = en->engine->imConfig->get_key_switch() ? "1" : "2";
            res.set_content("{\"state\":" + tmp + "}", "application/json");
        } else {
            res.set_content("{\"code\":300}", "application/json");
        }
    });
    en->server->Options("/symbols",
                        [](const httplib::Request &, httplib::Response &resp) {
                            resp.status = 200;
                        });
    en->server->Get("/symbols", [&en](const httplib::Request &req,
                                      httplib::Response &res) {
        if (req.has_param("value")) {
            auto val = req.get_param_value("value");
            InputSymbols(val,en);
            system("xdotool getactivewindow > ~/.window_id");
            res.set_content("{\"code\":200}", "application/json");
        } else if (req.params.empty()) {
            res.set_content("{\"state\":1}", "application/json");
        } else {
            res.set_content("{\"code\":300}", "application/json");
        }
    });
    en->server->listen("127.0.0.1", 56181);
}

#endif // FCITX_SERVER_H
